package com.thinkgem.jeesite.modules.wx.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.thinkgem.jeesite.modules.wx.dao.WxConfigDao;
import com.thinkgem.jeesite.modules.wx.entity.WxConfig;
import com.thinkgem.jeesite.modules.wx.entity.WxMpDBConfigStorage;
import com.thinkgem.jeesite.modules.wx.handler.AbstractHandler;
import com.thinkgem.jeesite.modules.wx.handler.KfSessionHandler;
import com.thinkgem.jeesite.modules.wx.handler.LocationHandler;
import com.thinkgem.jeesite.modules.wx.handler.LogHandler;
import com.thinkgem.jeesite.modules.wx.handler.MenuHandler;
import com.thinkgem.jeesite.modules.wx.handler.MsgHandler;
import com.thinkgem.jeesite.modules.wx.handler.NullHandler;
import com.thinkgem.jeesite.modules.wx.handler.StoreCheckNotifyHandler;
import com.thinkgem.jeesite.modules.wx.handler.SubscribeHandler;
import com.thinkgem.jeesite.modules.wx.handler.UnsubscribeHandler;

import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;

/**
 * 
 * @author Binary Wang
 *
 */
@Service
public class WeixinService extends WxMpServiceImpl {
	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	@Autowired
	private WxConfigDao wxConfigDao;

	@Autowired
	protected LogHandler logHandler;

	@Autowired
	protected NullHandler nullHandler;

	@Autowired
	protected KfSessionHandler kfSessionHandler;

	@Autowired
	protected StoreCheckNotifyHandler storeCheckNotifyHandler;

	@Autowired
	private LocationHandler locationHandler;

	@Autowired
	private MenuHandler menuHandler;

	@Autowired
	private MsgHandler msgHandler;

	@Autowired
	private UnsubscribeHandler unsubscribeHandler;

	@Autowired
	private SubscribeHandler subscribeHandler;

	private WxMpMessageRouter router;
	
	public WxMpService getApi(String key){
		WxConfig wxConfig = wxConfigDao.get(key);
		if(null != wxConfig){
			final WxMpDBConfigStorage config = getMpConfigStorage(wxConfig);
			this.setWxMpConfigStorage(config);
		}
		return this;
	}

	/**
	 * 
	 * @Description 处理用户消息时的签名验证 <br/>
	 * @author sea
	 * @Date 2017年5月19日 下午2:47:08 <br/>
	 * @param timestamp
	 * @param nonce
	 * @param signature
	 * @param key
	 * @return
	 */
	public boolean check(String timestamp, String nonce, String signature, String key){
		WxConfig wxConfig = wxConfigDao.get(key);
		if(null != wxConfig){
			final WxMpDBConfigStorage config = getMpConfigStorage(wxConfig);
			super.setWxMpConfigStorage(config);
			this.refreshRouter();
		}else{
			return false;
		}
		return super.checkSignature(timestamp, nonce, signature);
	}

	/**
	 * 
	 * @Description 获取调用微信公众号api的配置信息<br/>
	 * @author sea
	 * @Date 2017年5月22日 上午9:08:33 <br/>
	 * @param wxConfig
	 * @return
	 */
	private WxMpDBConfigStorage getMpConfigStorage(WxConfig wxConfig) {
		final WxMpDBConfigStorage config = new WxMpDBConfigStorage();
		config.setAppId(wxConfig.getAppid());// 设置微信公众号的appid
		config.setSecret(wxConfig.getAppsecret());// 设置微信公众号的app corpSecret
		config.setToken(wxConfig.getToken());// 设置微信公众号的token
		config.setAesKey(wxConfig.getEncodingaeskey());// 设置消息加解密密钥
		config.setWxConfig(wxConfig);
		config.setWxConfigDao(wxConfigDao);
		return config;
	}

	private void refreshRouter() {
		final WxMpMessageRouter newRouter = new WxMpMessageRouter(this);

		// 记录所有事件的日志
		newRouter.rule().handler(this.logHandler).next();

		// 接收客服会话管理事件
		newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT).event(WxConsts.EVT_KF_CREATE_SESSION)
				.handler(this.kfSessionHandler).end();
		newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT).event(WxConsts.EVT_KF_CLOSE_SESSION)
				.handler(this.kfSessionHandler).end();
		newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT).event(WxConsts.EVT_KF_SWITCH_SESSION)
				.handler(this.kfSessionHandler).end();

		// 门店审核事件
		newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT).event(WxConsts.EVT_POI_CHECK_NOTIFY)
				.handler(this.storeCheckNotifyHandler).end();

		// 自定义菜单事件
		newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT).event(WxConsts.BUTTON_CLICK)
				.handler(this.getMenuHandler()).end();

		// 点击菜单连接事件
		newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT).event(WxConsts.BUTTON_VIEW)
				.handler(this.nullHandler).end();

		// 关注事件
		newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT).event(WxConsts.EVT_SUBSCRIBE)
				.handler(this.getSubscribeHandler()).end();

		// 取消关注事件
		newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT).event(WxConsts.EVT_UNSUBSCRIBE)
				.handler(this.getUnsubscribeHandler()).end();

		// 上报地理位置事件
		newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT).event(WxConsts.EVT_LOCATION)
				.handler(this.getLocationHandler()).end();

		// 接收地理位置消息
		newRouter.rule().async(false).msgType(WxConsts.XML_MSG_LOCATION).handler(this.getLocationHandler()).end();

		// 扫码事件
		newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT).event(WxConsts.EVT_SCAN)
				.handler(this.getScanHandler()).end();

		// 默认
		newRouter.rule().async(false).handler(this.getMsgHandler()).end();

		this.router = newRouter;
	}

	public WxMpXmlOutMessage route(WxMpXmlMessage message) {
		try {
			return this.router.route(message);
		} catch (Exception e) {
			this.logger.error(e.getMessage(), e);
		}

		return null;
	}
	
	public boolean hasKefuOnline() {
		try {
			WxMpKfOnlineList kfOnlineList = this.getKefuService().kfOnlineList();
			return kfOnlineList != null && kfOnlineList.getKfOnlineList().size() > 0;
		} catch (Exception e) {
			this.logger.error("获取客服在线状态异常: " + e.getMessage(), e);
		}

		return false;
	}

	protected MenuHandler getMenuHandler() {
		return this.menuHandler;
	}

	protected SubscribeHandler getSubscribeHandler() {
		return this.subscribeHandler;
	}

	protected UnsubscribeHandler getUnsubscribeHandler() {
		return this.unsubscribeHandler;
	}

	protected AbstractHandler getLocationHandler() {
		return this.locationHandler;
	}

	protected MsgHandler getMsgHandler() {
		return this.msgHandler;
	}

	protected AbstractHandler getScanHandler() {
		return null;
	}

}
